package com.browsesoft.htmlcomponent;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.aote.page.PageException;
import com.aote.util.ThreadLocals;
import com.browsesoft.ExtendElement;
import com.browsesoft.ManagerGroup;
import com.browsesoft.PropertiesService;
import com.browsesoft.oa.BSHttpServletRequest;
import com.browsesoft.oa.CssStyle;
import com.browsesoft.user.User;

/**
 * HTML页面
 * 
 * @author Browsesoft
 * @version 1.0
 */
public final class HTMLPage extends HTMLBasicComponent {
	/**
	 * 当前登录用户
	 */
	private User loginuser = null;

	/**
	 * HTML的文档内容
	 */
	private Document document = null;

	/**
	 * 上次页面调用时间，返回System.currentTimeMillis()的值
	 */
	private long time = System.currentTimeMillis();

	/**
	 * 是否被锁定
	 */
	private boolean isLocked = false;

	/**
	 * 保存所有的在线用户，用户登录的时候自动登记， 用户退出的时候删除， 用户如果超过响应时间视为离线
	 */
	private static Hashtable onlineUsers = new Hashtable();

	/**
	 * 保存所有的在线用户的最后一次请求时间，
	 */
	private static Hashtable requestTimes = new Hashtable();

	/**
	 * 跳转列表
	 */
	protected SkipList skipList = null;

	/**
	 * 上一个页面的pagename
	 */
	protected String previewname = null;

	/**
	 * 错误列表
	 */
	protected LinkedList errorList = new LinkedList();

	/**
	 * onload的初始值
	 */
	private String oldOnload;

	/**
	 * 调用open等方法时，保存的onload值
	 */
	private String onload = "";

	/**
	 * 调用close时，保存的值
	 */
	private String closeString = "";

	/**
	 * 印章控件的onload
	 */
	private String signOnload = "";

	/**
	 * 页面所对应的模版名称
	 */
	private String templateName;

	/**
	 * 构造器
	 * 
	 * @param parent
	 *            组件的父组件
	 * @throws Exception
	 */
	public HTMLPage(HTMLBasicComponent parent) throws Exception {
		super(parent);
	}

	/**
	 * 取得HTML的文档内容
	 * 
	 * @return 文档内容
	 */
	public Document getDocument() {
		return document;
	}

	/**
	 * 取得页面名称
	 * 
	 * @return 页面名称
	 */
	public String getName() {
		return name;
	}

	/**
	 * 返回上次页面调用时间
	 * 
	 * @return 时间
	 */
	public long getTime() {
		return time;
	}

	/**
	 * 根据请求，设置模板并生成组件
	 * 
	 * @param request
	 *            请求
	 * @param templateName
	 *            模板名
	 * @throws Exception
	 */
	public void setTemplateName(HttpServletRequest request, String templateName)
			throws Exception {
		this.templateName = templateName;
		// 加载模板
		TemplateManager manager = (TemplateManager) ManagerGroup
				.getManagerGroup().getManager("template");
		// 根据模板名生成模板
		Template t = manager.getTemplateByName(templateName);
		// 如果没有得到模板
		if (t == null) {
			throw new RuntimeException("模板(" + templateName + ")不存在");
		}
		// 得到模板文档
		this.document = t.getDocument();
		// 解析文档,找出需要处理的根元素
		Element element = (Element) document.getElementsByTagName("body").item(
				0);
		// 产生子组件
		// this.getComponents(element);
		init(request, element);
	}

	/**
	 * 根据HTMLModel以及HTML文件，生成HTML页面 后代一般要重载updateElements方法，不用重载该方法
	 * 
	 * @return HTML页面
	 */
	public String createHTML() {
		String result;
		try {
			this.update();
			// 生成转换对象
			Transformer trans = TransformerFactory.newInstance()
					.newTransformer();
			String encoding = PropertiesService.getProperty("HtmlCharacterSet",
					"type");
			trans.setOutputProperty("encoding", encoding);
			Element root = (Element) this.getDocument().getDocumentElement();
			// 得到转换源
			DOMSource domSource = new DOMSource(root);
			// 得到转换结果
			ByteArrayOutputStream os = new ByteArrayOutputStream();
			// 转换
			trans.transform(domSource, new StreamResult(os));
			// 得到转换结果
			result = os.toString();
			// 把|B|换成<
			result = result.replaceAll("#B#", "<");
			// 把|S|换成>
			result = result.replaceAll("#S#", ">");
		} catch (Exception e) {
			e.printStackTrace();
			// return "操作失败";
			return "<html xmlns='http://www.w3.org/1999/xhtml'>"
					+ "<head><meta http-equiv='Content-Type' content='text/html; charset=GBK' />"
					+ "<title></title><link href='../css/style_01.css' rel='stylesheet' type='text/css' />"
					+ "<style type='text/css'><!--body {background-image: url(../images/report.jpg);}-->"
					+ "</style></head><body></body></html>";
		} finally {
			this.isLocked = false;
		}
		return result;

	}

	/**
	 * 接受界面参数，更新
	 * 
	 * @param request
	 *            请求
	 * @param response
	 *            响应
	 * @throws Exception
	 */
	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		// 如果没有被锁定
		if (!isLocked) {
			this.isLocked = true;
		} else {
			return;
		}
		// 设置当前最新请求
		super.service(request, response);
		// 设置页面调用时间
		time = System.currentTimeMillis();
		scroll(request);
		// 注册用户
		setUserLogin(request);
	}

	public String disposePage(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		request = new BSHttpServletRequest(request);
		// 设置线程局部变量
		ThreadLocals.loginUser.set(this.loginuser);
		ThreadLocals.page.set(this);
		ThreadLocals.request.set(request);
		ThreadLocals.response.set(response);
		try {
			this.dispatch(request, response);
			String html = this.createHTML();
			return html;
		} catch (PageException e) {
			String str = "<body onload=\"alert('" + e.getMessage()
					+ "');history.back();\">";
			return str;
		}
	}

	/**
	 * 设置body的onload属性
	 */
	public void setOnload() {
		// 追加oldOnload
		this.onload = this.addOnload(this.onload, this.signOnload);
		this.onload = this.addOnload(this.onload, this.oldOnload);
		this.onload = this.addOnload(this.onload, this.closeString);
		this.element.setAttribute("onload", this.onload);
		this.onload = "";
		this.closeString = "";
	}

	protected void updateElement() throws Exception {
		super.updateElement();
		// 根据请求得到满足条件的跳转
		HttpServletRequest request = (HttpServletRequest) ThreadLocals.request
				.get();
		HttpServletResponse response = (HttpServletResponse) ThreadLocals.response
				.get();
		Map map = request.getParameterMap();
		Skip skip = this.skipList.getSkip(map);
		if (skip != null) {
			// 跳转到相应的页面
			skip.skip(response);
		}
		// 根据动作决定页面跳转方向
		doAction(request, response);
		this.setOnload();
	}

	/**
	 * 给onload追加信息
	 */
	public String addOnload(String str, String msg) {
		String result = str;
		// 如果没有分号，添加分号
		if (!result.equals("") && !result.endsWith(";")) {
			result += ";";
		}
		result += msg;
		return result;
	}

	public void addOnload(String msg) {
		this.onload = this.addOnload(this.onload, msg);
	}

	/**
	 * 滚动到上次点击位置
	 * 
	 * @param request
	 */
	private void scroll(HttpServletRequest request) {
		// 得到参数传递过来的位置
		String x = "0";
		String y = "0";
		if (request.getParameter("xlocation") != null
				&& !request.getParameter("xlocation").equals("")) {
			x = request.getParameter("xlocation");
		}
		if (request.getParameter("ylocation") != null
				&& !request.getParameter("ylocation").equals("")) {
			y = request.getParameter("ylocation");
		}
		String value = "window.scrollTo(" + x + ", " + y + ");";
		this.onload = this.addOnload(this.onload, value);
	}

	/**
	 * 根据动作决定页面跳转方向
	 * 
	 * @param request
	 * @param response
	 * @throws Exception
	 * @throws IOException
	 */
	private void doAction(HttpServletRequest request,
			HttpServletResponse response) throws Exception, IOException {
		// 得到action值
		String action = request.getParameter("action");
		if (action != null) {
			// 如果是连续添加动作
			if (action.equals("continue")) {
				// 如果没有错误
				if (this.errorList.size() == 0) {
					Element elem = (Element) ExtendElement.findElementsOfAttr(
							this.element, "continue").get(0);
					String toPage = elem.getAttribute("continue");
					this.open(toPage);
				}
			}
			// 如果提交或返回
			else if ((action.equals("confirm") || action.equals("return") || action
					.equals("tijiao"))
					&& this.previewname != null
					&& !this.previewname.equals("")
					&& this.previewname.indexOf("page_name") == -1) {
				if (action.equals("confirm") || action.equals("tijiao")) {
					// 如果没有错误
					if (this.errorList.size() == 0) {
						// 重定向到前一个页面
						response.sendRedirect("page.jsp?pagename="
								+ this.previewname);
						request.getSession().removeAttribute(this.getName());
					}
				} else if (action.equals("return")) {
					response.sendRedirect("page.jsp?pagename="
							+ this.previewname);
					request.getSession().removeAttribute(this.getName());
				}
			}
		}
	}

	/**
	 * 看页面是否已经失效
	 * 
	 * @return 是否已经失效
	 */
	public boolean isInvalid() {
		try {
			// 从设置中取出失效时间（单位:分钟）
			int timeOut = Integer.parseInt(PropertiesService.getProperty(
					"time", "timeout"));
			// 当前系统时间
			long systemTime = System.currentTimeMillis();
			long time = systemTime - this.getTime();
			boolean isInvalid = time > timeOut * 60000;
			return isInvalid;
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/**
	 * 取得某种类型的所有组件
	 * 
	 * @param className
	 *            类名
	 * @return 组件
	 * @throws Exception
	 */
	public LinkedList getComponentsByClassName(String className)
			throws Exception {
		LinkedList result = new LinkedList();
		Class c = Class.forName(className);
		for (int i = 0; i < components.size(); i++) {
			Object component = components.get(i);
			if (c.isInstance(component)) {
				result.add(component);
			}
		}
		return result;
	}

	/**
	 * 初始化时创建子组件并设置初始化参数
	 * 
	 * @param request
	 *            请求
	 * @param e
	 *            元素
	 * @throws Exception
	 */
	public void init(HttpServletRequest request, Element e) throws Exception {
		loginuser = (User) request.getSession().getAttribute("loginUser");
		request = new BSHttpServletRequest(request);
		this.oldOnload = e.getAttribute("onload");
		// 替换上一个页面的pagename
		this.replacePreviewPagename(e);
		super.init(request, e);
		// 设置风格为当前用户的个性化风格，有异常，说明在属性文件里没有声明替换样式，不替换
		try {
			PropertiesService.getProperty("style", "replace");
			this.replaceStyle(request, e);
		} catch (Exception ex) {
		}
		processFormAction(e);
		// 构造跳转列表
		this.skipList = new SkipList(this.getElement());
		// 得到page_name
		this.previewname = request.getParameter("page_name");
		// 添加aciton隐藏域
		this.addActionHidden(e);
	}

	/**
	 * 处理form的action，如果有#pagename#，则替换之。
	 * 
	 * @param e
	 */
	private void processFormAction(Element e) {
		// 得到form
		NodeList nl = e.getElementsByTagName("form");
		// 如果有
		if (nl.getLength() > 0) {
			// 替换所有属性中的#pagename#为页面名称
			Element form = (Element) nl.item(0);
			NamedNodeMap map = form.getAttributes();
			// 逐个替换并设置属性，解决有时页面号在多个地方出现的问题
			for (int i = 0; i < map.getLength(); i++) {
				Node node = map.item(i);
				String value = node.getNodeValue();
				value = value.replaceFirst("#pagename#", this.getName());
				String key = node.getNodeName();
				form.setAttribute(key, value);
			}
		}
	}

	/**
	 * 添加action隐藏域，防止画表单时，忘记画action隐藏域
	 */
	private void addActionHidden(Element e) {
		// 得到form，在form下添加
		NodeList nl = e.getElementsByTagName("form");
		// 没有form，不添加
		if (nl.getLength() != 1) {
			return;
		}
		Element eForm = (Element) nl.item(0);
		// 有action，不添加
		List list = ExtendElement.findElements(eForm, "name", "action");
		if (list.size() == 1) {
			return;
		}
		// 添加action隐藏域
		Element elem = eForm.getOwnerDocument().createElement("input");
		elem.setAttribute("type", "hidden");
		elem.setAttribute("name", "action");
		eForm.appendChild(elem);
		// 添加其他事件隐藏域
		Element element = eForm.getOwnerDocument().createElement("input");
		element.setAttribute("type", "hidden");
		element.setAttribute("name", "otheraction");
		eForm.appendChild(element);
	}

	/**
	 * 弹出提示对话筐
	 * 
	 * @param message
	 *            提示内容
	 */
	public void showMessage(String message) {
		this.onload = this.addOnload(this.onload, message);
	}

	/**
	 * 得到关闭语句
	 * 
	 * @return 关闭语句
	 */
	public String getCloseSentence() {
		Element body = (Element) this.getElement();
		String close = body.getAttribute("close");
		if (close.equals("")) {
			return ";";
		} else {
			return close;
		}
	}

	/**
	 * 得到刷新语句
	 * 
	 * @return 刷新语句
	 */
	public String getRefreshSentence() {
		Element body = (Element) this.getElement();
		String refresh = body.getAttribute("refresh");
		if (refresh.equals("")) {
			return ";";
		} else {
			return refresh;
		}
	}

	/**
	 * 页面的关闭方法,如果body中有close属性，用close中的关闭方法,否则默认关闭
	 */
	public void close() {
		String close = getCloseSentence();
		this.closeString = this.addOnload(this.closeString, close);
	}

	/**
	 * 关闭页面，如果页面上没有配置close，用给定参数关闭
	 */
	public void close(String str) {
		this.closeString = this.addOnload(this.closeString, str);
	}

	/**
	 * 页面刷新，父页面刷新，框架刷新，body中有refresh属性
	 */
	public void refresh() {
		String refresh = this.getRefreshSentence();
		this.onload = this.addOnload(this.onload, refresh);
	}

	public String getOpenSentence() {
		Element body = (Element) this.getElement();
		String open = body.getAttribute("open");
		return open;
	}

	public void open() {
		String open = this.getOpenSentence();
		this.onload = this.addOnload(this.onload, open);
	}

	/**
	 * 打开新的页面
	 * 
	 * @param OpenSentence
	 *            打开句子
	 */
	public void open(String OpenSentence) {
		this.onload = this.addOnload(this.onload, OpenSentence);
	}

	/**
	 * 注册用户 用户登录与主页面刷新的时候使用
	 * 
	 * @param request
	 *            请求
	 */
	public void setUserLogin(HttpServletRequest request) {
		// 得到当前的登录用户
		Object loginUser = request.getSession().getAttribute("loginUser");
		if (loginUser != null) {
			// 获得用户id
			String userID = ((User) loginUser).getID();
			// 判断登录用户是否存在，如果不存在，就把当前登录用户添加进来
			if (!onlineUsers.contains(loginUser)) {
				// 添加用户
				onlineUsers.put(userID, loginUser);
			}
			// 修改请求时间
			requestTimes.put(userID, new Long(time));
		} // end if
	}

	/**
	 * 设置用户离开 在用户点退出离开的时候调用
	 * 
	 * @param userID
	 *            当前用户的用户ID
	 */
	public void setUserLeft(String userID) {
		// 判断登录用户是否存在，如果不存在，就把当前登录用户添加进来
		if (onlineUsers.keySet().contains(userID)) {
			onlineUsers.keySet().remove(userID);
			requestTimes.keySet().remove(userID);
		}
	}

	/**
	 * 设置用户因超时没有请求而离开 在用户点退出离开的时候调用
	 * 
	 * @param timeOutSecond
	 *            超时（单位为：秒）
	 */
	public void setUserTimeOut(int timeOutSecond) {
		// 定义超时（单位毫秒）
		long timeOutMillsec = timeOutSecond * 1000;
		// 获得当前的时间
		long currentTime = System.currentTimeMillis();
		// 获得当前在线用户的迭代
		Hashtable users = new Hashtable(); // 中间状态变量，保持上次的所有在线用户
		users.putAll(onlineUsers);
		Iterator it = users.keySet().iterator();
		// 对每一个在线用户判断是否超时离开
		while (it.hasNext()) {
			String userID = (String) it.next();
			// 获得超时的毫秒数
			Long lastTime = (Long) requestTimes.get(userID);
			long gapTime = currentTime - lastTime.longValue();
			// 判断在线用户是否超时，如果超时，就从在线用户列表中删除
			if (gapTime > timeOutMillsec) {
				setUserLeft(userID);
			} // end if
		} // end while
	}

	/**
	 * 得到当前的所有在线用户
	 * 
	 * @return 当前的所有在线用户的哈西表
	 */
	public Hashtable getOnLineUsers() {
		return HTMLPage.onlineUsers;
	}

	/**
	 * 替换link元素中的href属性值，如果style有多个，只取第一个
	 * 
	 * @param request
	 *            请求
	 * @param element
	 *            元素
	 */
	protected void replaceStyle(HttpServletRequest request, Element element) {
		// 取得当前用户
		User user = (User) request.getSession().getAttribute("loginUser");
		if (user == null) {
			return;
		}
		// 取得当前用户的Style
		CssStyle style = user.getCssStyle();
		// 如果为styleid为 "" 则说明是为默认风格，此时说明都不做，直接返回。
		if (style == null || (style.getAttributes().get("id")).equals("")) {
			return;
		}
		// 取得stylesheet的名字和路径
		String styleSheetName = style.getStyleSheetName();
		// 如果stylesheetname不存在或者path不存在就什么也不做，直接返回
		if (styleSheetName == null) {
			return;
		}
		if (styleSheetName.equals("null")) {
			return;
		}
		// 取得当前页面中的 link 元素集
		Element e = element.getOwnerDocument().getDocumentElement();
		Iterator iter = ExtendElement.findElements(e, "rel", "stylesheet")
				.iterator();
		// 如果找到了
		if (iter.hasNext()) {
			// 取一个
			Element oldLinkElement = (Element) iter.next();
			// 换
			String value = "../css/" + styleSheetName;
			oldLinkElement.setAttribute("href", value);
		}
	}

	/**
	 * 得到当前的登录用户
	 * 
	 * @return 当前的登录用户
	 */
	public User getLoginUser() {
		return this.loginuser;
	}

	/**
	 * 跳转
	 */
	class Skip {
		protected String key;

		protected String value;

		protected String templatename = null;

		/**
		 * 构造函数
		 * 
		 * @param e
		 *            跳转对应的元素
		 */
		public Skip(Element e) {
			String condition = e.getAttribute("condition");
			this.key = condition.substring(0, condition.indexOf("="));
			this.value = condition.substring(condition.indexOf("=") + 1);
			this.templatename = e.getAttribute("templatename");
		}

		/**
		 * 跳转
		 * 
		 * @param response
		 *            响应
		 * @throws Exception
		 */
		protected void skip(HttpServletResponse response) throws Exception {
			// 跳转到相应页面
			templatename = new String(templatename.getBytes(), "iso8859-1");
			response.sendRedirect("page.jsp?templatename=" + templatename);
		}
	}

	/**
	 * 跳转列表
	 */
	class SkipList {
		Map skips = new HashMap();

		/**
		 * 构造函数
		 * 
		 * @param element
		 *            元素
		 */

		public SkipList(Element element) {
			// 得到所有跳转
			LinkedList ls = ExtendElement.findElements(element, "type",
					"forward");
			// 对于每一个跳转
			Iterator iter = ls.iterator();
			while (iter.hasNext()) {
				Skip skip = new Skip((Element) iter.next());
				skips.put(skip.key + "=" + skip.value, skip);
			}
		}

		/**
		 * 得到满足条件的跳转
		 * 
		 * @param map
		 *            页面上传过来的map
		 * @return 符合条件的跳转
		 * @throws Exception
		 */
		protected Skip getSkip(Map map) throws Exception {
			Iterator iter = skips.keySet().iterator();
			while (iter.hasNext()) {
				String key = (String) iter.next();
				Skip skip = (Skip) skips.get(key);
				String[] value = (String[]) map.get(skip.key);
				if (value != null && value.length > 0) {
					String v = value[0];
					if ((skip.key + "=" + v)
							.equals(skip.key + "=" + skip.value)) {
						return skip;
					}
				}
			}
			return null;
		}
	}

	/**
	 * 在需要右下方打开窗口的按钮上替换上一个页面的pagename
	 * 
	 * @param e
	 *            组件元素
	 * @throws Exception
	 */
	public void replacePreviewPagename(Element e) throws Exception {
		// 得到所有带onclick属性的元素
		LinkedList ls = ExtendElement.findElementsOfAttr(e, "onclick");
		// 对于每一个有onclick属性的元素
		Iterator iter = ls.iterator();
		while (iter.hasNext()) {
			// 替换page_name
			Element element = (Element) iter.next();
			String onclick = element.getAttribute("onclick");
			if (onclick.indexOf("page_name") != -1) {
				onclick = onclick.replaceAll("page_name=#page_name#",
						"page_name=" + this.getName());
				element.setAttribute("onclick", onclick);
			}
		}
	}

	public String getSignOnload() {
		return this.signOnload;
	}

	public void setSignOnload(String string) {
		this.signOnload = string;
	}

	/**
	 * 显示错误信息，显示信息的同时，登记显示过错误信息了
	 */
	public void showError(String error) {
		this.showMessage(error);
	}

	/**
	 * 得到模版名
	 */
	public String getTempalteName() {
		return this.templateName;
	}

}